﻿using System;
using System.Collections;
using System.Collections.Generic;
using System.Collections.Specialized;
using System.Net;
using System.Text;
using System.Web.Script.Serialization;
using HtmlAgilityPack;
using FileSystemDatabase;
using Newtonsoft.Json.Linq;
using TomatoSynchronizer.Entities;
using Newtonsoft.Json;
using System.IO;

namespace TomatoSynchronizer.Store
{
	public class CategoryStore : IStore<Category>
	{
		private Site _site;
		public Site site {
			get { return _site; }
			set { _site = value; }
		}
		
		private HtmlWeb _client;
		private List<Category> _allCategories;
		JavaScriptSerializer serialiser;

		private Category[] _categories;

		private JsonDatabase db;
		public void PersistItems(List<Category> Categories)
		{
			db.Write<List<Category>>(Categories, _site.Name);
		}

		public void Truncate()
		{
			LoadItems();
			if(_categories != null)
			{
				foreach (Category category in _categories)
				{
					if(!DeleteItem(category.categories_id))
					{
						throw new Exception("Could not delete the category " + category.categories_name);
					}
				}
			}

			db.Truncate();
		}

		public bool DeleteItem(string categoryId)
		{
			HtmlDocument doc = _client.Load(_site.Url + "/admin/json.php?action=delete_category&categories_id=" + categoryId + "&module=categories");

			HtmlNode node = doc.DocumentNode.SelectSingleNode("/");

			IDictionary json = serialiser.Deserialize<IDictionary>(node.InnerText);
			foreach (string key in json.Keys) {
				if (key == "success") {
					string response = json[key].ToString();
					return bool.Parse(response);
				}
			}

			return false;
		}

		public void PersistItem(Category category)
		{
			db.Write<Category>(category, category.categories_id);
		}

		public Category[] LoadItems()
		{
			_categories = db.Read<Category>();
			
			foreach(Category category in _categories)
			{
				category.Store = this;
			}
			
			return _categories;
		}

		public Category LoadItem(string itemId)
		{
			Category category = db.Read<Category>(itemId);
			if(category != null)
			{
				category.Store = this;
				return category;
			}
			
			return null;
		}

		public bool Contains(Category category)
		{
			foreach (Category categoryDest in _categories) {
				if (category.categories_name == categoryDest.categories_name) {
					return true;
				}
			}

			return false;
		}

		public CategoryStore(Site site, HtmlWeb client)
		{
			db = new JsonDatabase("sites/" + site.Name + "/Categories");
			_site = site;
			_client = client;
			serialiser = new JavaScriptSerializer();
			_allCategories = new List<Category>();
		}

		public CategoryStore()
		{
		}
		
		private void SynchroniseCategories()
		{
			GetItems();
		}

		public List<Category> GetItems()
		{
			db.Truncate();

			List<Category> rootCategories = GetCategories("0");

			_allCategories.AddRange(rootCategories);

			foreach (Category category in rootCategories) {
				GetSubItems(category);
			}

			return _allCategories;
		}

		public Category GetItem(string categoryId)
		{
			JObject json = null;

			HtmlDocument categoryDocument = _client.Load(_site.Url + "/admin/json.php?action=load_category&categories_id=" + categoryId + "&module=categories");

			if (categoryDocument.DocumentNode != null) {
				foreach (HtmlNode node in categoryDocument.DocumentNode.SelectNodes("/")) {
					json = (JObject)JsonConvert.DeserializeObject(node.InnerText);
					foreach (JProperty property in json.Properties()) {
						if (property.Name == "data") {
							Category category = new Category(property.Value.ToString());
							if (category != null) {
								Utility.DownloadImage(_site.Url + "/images/categories/" + category.categories_image);
								category.Store = this;
								return category;
							}
						}
					}
				}
			}

			//throw new Exception("Unable to load the category " + categoryId + " in site " + _site.Name);
			return null;
		}

		public bool MoveItem(string categoryId, string parent_id)
		{
			HtmlDocument doc = _client.Load(_site.Url + "/admin/json.php?action=move_categories&categories_ids=" + categoryId + "&module=categories&parent_category_id=" + parent_id);

			JavaScriptSerializer serialiser = new JavaScriptSerializer();
			if (doc.DocumentNode != null) {
				foreach (HtmlNode node in doc.DocumentNode.SelectNodes("/")) {
					IDictionary json = serialiser.Deserialize<IDictionary>(node.InnerText);
					if (json != null) {
						foreach (string key in json.Keys) {
							if (key == "success") {
								return bool.Parse(json[key].ToString());
							}
						}
					}
				}
			}

			return false;
		}

		public bool UpdateItem(Category category)
		{
			CookieContainer cookies = new CookieContainer();

			NameValueCollection querystring = new NameValueCollection();

			querystring["categories_id"] = category.categories_id;
			querystring["parent_category_id"] = category.parent_id;
			querystring["categories_url"] = category.categories_url;
			querystring["categories_name"] = category.categories_name;
			querystring["parentId"] = category.parent_id;
			querystring["sort_order"] = category.sort_order;
			querystring["categories_status"] = category.categories_status;
			querystring["page_title"] = category.page_title != null ? category.page_title : category.categories_name;
			querystring["meta_keywords"] = category.meta_keywords != null ? category.meta_keywords : "";
			querystring["meta_description"] = category.meta_description != null ? category.meta_description : "";
			querystring["ratings"] = "";
			querystring["module"] = "categories";
			querystring["action"] = "save_category";
			
			foreach(string key in category.categories_names.Keys)
			{
				querystring[key] = category.categories_names[key];
			}

			foreach(string key in category.categories_urls.Keys)
			{
				querystring[key] = category.categories_urls[key];
			}

			foreach(string key in category.meta_descriptions.Keys)
			{
				querystring[key] = category.meta_descriptions[key];
			}

			foreach(string key in category.meta_keywordss.Keys)
			{
				querystring[key] = category.meta_keywordss[key];
			}
			
			foreach(string key in category.page_titles.Keys)
			{
				querystring[key] = category.page_titles[key];
			}
			
			string uploadfile = "dummy.txt";
			
			if(!string.IsNullOrEmpty(category.categories_image))
			{
				uploadfile = category.categories_image;
			}		

			string response = Utility.UploadFileEx(uploadfile, _site.Url + "/admin/json.php", "image", "image/pjpeg", querystring, cookies);
			JavaScriptSerializer serialiser = new JavaScriptSerializer();
			IDictionary json = serialiser.Deserialize<IDictionary>(response);
			if (json != null) {
				foreach (string key in json.Keys) {
					if (key == "success") {
						PersistItem(category);
						return MoveItem(category.categories_id, category.parent_id);
					}
				}
			}

			return false;
		}

		public string InsertItem(Category category)
		{
			CookieContainer cookies = new CookieContainer();

			NameValueCollection querystring = new NameValueCollection();

			querystring["parent_category_id"] = category.parent_id;
			querystring["categories_url"] = category.categories_url;
			querystring["categories_name"] = category.categories_name;
			querystring["parentId"] = category.parent_id;
			querystring["sort_order"] = category.sort_order;
			querystring["categories_status"] = category.categories_status;
			querystring["page_title"] = category.page_title != null ? category.page_title : category.categories_name;
			querystring["meta_keywords"] = category.meta_keywords != null ? category.meta_keywords : "";
			querystring["meta_description"] = category.meta_description != null ? category.meta_description : "";
			querystring["ratings"] = "";
			querystring["module"] = "categories";
			querystring["action"] = "save_category";
			
			foreach(string key in category.categories_names.Keys)
			{
				querystring[key] = category.categories_names[key];
			}

			foreach(string key in category.categories_urls.Keys)
			{
				querystring[key] = category.categories_urls[key];
			}

			foreach(string key in category.meta_descriptions.Keys)
			{
				querystring[key] = category.meta_descriptions[key];
			}

			foreach(string key in category.meta_keywordss.Keys)
			{
				querystring[key] = category.meta_keywordss[key];
			}
			
			foreach(string key in category.page_titles.Keys)
			{
				querystring[key] = category.page_titles[key];
			}
			
			string uploadfile = "dummy.txt";
			
			if(!string.IsNullOrEmpty(category.categories_image))
			{
				uploadfile = category.categories_image;
			}

			string response = Utility.UploadFileEx(uploadfile, _site.Url + "/admin/json.php", "image", "image/pjpeg", querystring, cookies);

			JavaScriptSerializer serialiser = new JavaScriptSerializer();
			IDictionary json = serialiser.Deserialize<IDictionary>(response);
			if (json != null) {
				foreach (string key in json.Keys) {
					if (key == "categories_id") {
						return json[key].ToString();
					}
				}
			}

			return string.Empty;
		}

		private void GetSubItems(Category parentCategory)
		{
			List<Category> subCategories = GetCategories(parentCategory.categories_id);
			_allCategories.AddRange(subCategories);
			foreach (Category category in subCategories) {
				GetSubItems(category);
			}
		}

		private List<Category> GetCategories(string parentId)
		{
			List<Category> categories = new List<Category>();

			HtmlDocument rootCategoriesDoc = _client.Load(_site.Url + "/admin/json.php?action=list_categories&categories_id=" + parentId + "&module=categories");

			if (rootCategoriesDoc.DocumentNode != null) {
				foreach (HtmlNode node in rootCategoriesDoc.DocumentNode.SelectNodes("/")) {
					try {
						IDictionary json = serialiser.Deserialize<IDictionary>(node.InnerText);
						if (json != null) {
							foreach (string key in json.Keys) {
								if (key == "records") {
									object[] list = (object[])json[key];

									if (list != null) {
										for (int i = 0; i < list.Length; i++) {
											IDictionary category = (IDictionary)list[i];
											if (category != null) {
												Category item = GetItem(category["categories_id"].ToString());
												categories.Add(item);
											}
										}
									}
								}
							}
						}
					} catch (ArgumentException) {
					}
				}
			}

			return categories;
		}
	}
}
